package com.zzyl.service.impl;

import com.zzyl.constant.Constants;
import com.zzyl.dto.UserLoginRequestDto;
import com.zzyl.entity.Member;
import com.zzyl.mapper.MemberMapper;
import com.zzyl.properties.JwtTokenManagerProperties;
import com.zzyl.service.MemberService;
import com.zzyl.service.WechatService;
import com.zzyl.utils.JwtUtil;
import com.zzyl.utils.ObjectUtil;
import com.zzyl.utils.StringUtils;
import com.zzyl.vo.LoginVo;
import lombok.extern.slf4j.Slf4j;
import org.assertj.core.util.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
public class MemberServiceImpl implements MemberService {

    @Autowired
    private WechatService wechatService;
    @Autowired
    private MemberMapper memberMapper;
    @Autowired
    private JwtTokenManagerProperties jwtTokenManagerProperties;

    static ArrayList DEFAULT_NICKNAME_PREFIX = Lists.newArrayList(
            "生活更美好",
            "大桔大利",
            "日富一日",
            "好柿开花",
            "柿柿如意",
            "一椰暴富",
            "大柚所为",
            "杨梅吐气",
            "天生荔枝"
    );


    /**
     * 小程序登录逻辑
     *
     * @param userLoginRequestDto 用户登录信息，包含微信登录所需的code和phoneCode
     * @return loginVo
     * OpenID 用户唯一标识
     * OpenID 生成流程
     *      微信接口服务：生成和管理 OpenID
     *      小程序端：提供临时凭证 code
     *      开发者服务器：用 code 换取 OpenID
     * OpenID 的特性
     *      特性	        说明
     *      生成者	    微信平台
     *      唯一性	    同一用户在同一公众号/小程序下唯一
     *      不变性	    对同一用户永远不变
     *      应用隔离	    不同小程序的OpenID不同
     *
     */
    @Override
    public LoginVo login(UserLoginRequestDto userLoginRequestDto) {
        log.info("用户登录请求: {}", userLoginRequestDto);
        // 1.调用微信api,根据code获取openId
        String openid = wechatService.getOpenid(userLoginRequestDto.getCode());
        log.info("获取到openid: {}", openid);
        // 2.根据openId查询用户
        // 一定要对类Member添加无参构造函数！！！当 MyBatis 无法找到合适的构造函数时，它会尝试其他方式创建对象，MyBatis 可能尝试使用某些内部机制来设置字段值，导致了类型转换错误
        // 项目中 com.zzyl.entity.Member.openId 是String类型，而MyBatis自动创建类Member的无参构造函数时，会默认为openId为Integer类型，从而导致类型转换错误！！！
        Member member = memberMapper.getByOpenId(openid);
        log.info("查询用户结果: {}", member);
        // 3.如果用户为空,则新增
        if (ObjectUtil.isEmpty(member)) {
            member = Member.builder().openId(openid).build();
        }
        // 4.调用微信api,获取用户绑定的手机号
        String phone = wechatService.getPhone(userLoginRequestDto.getPhoneCode());
        log.info("获取到手机号: {}", phone);
        // 5.保存or修改用户
        saveOrUpdate(member, phone);
        // 6.将用户id存入token,返回
        Map<String, Object> claims = new HashMap<>();
        claims.put(Constants.JWT_USERID, member.getId());
        claims.put(Constants.JWT_USERNAME,member.getName());
        // 开发者服务器生成JWT Token，不同于微信平台产生的 Token
        String token = JwtUtil.createJWT(jwtTokenManagerProperties.getBase64EncodedSecretKey(), jwtTokenManagerProperties.getTtl(), claims);
        LoginVo loginVo = new LoginVo();
        loginVo.setToken(token);
        loginVo.setNickName(member.getName());
        log.info("用户登录成功: {}", loginVo);
        return loginVo;
    }

    /**
     * 保存或修改用户
     *
     * @param member
     * @param phone
     */
    private void saveOrUpdate(Member member, String phone) {
        // 1.判断取到的手机号与数据库中是否一致
        if (ObjectUtil.notEqual(member.getPhone(), phone)) {
            // 设置手机号
            member.setPhone(phone);
        }
        // 2.判断id存在
        if (ObjectUtil.isNotEmpty(member.getId())) {
            // 更新用户
            memberMapper.update(member);
            return;
        }
        // 3.保存新的用户
        String nickName = DEFAULT_NICKNAME_PREFIX.get((int) (Math.random() * DEFAULT_NICKNAME_PREFIX.size()))
                + StringUtils.substring(member.getPhone(), 7);
        member.setName(nickName);
        memberMapper.save(member);
    }
}
